package com.qust.EnDecryption.listener;

import com.alibaba.fastjson2.JSON;
import com.qust.EnDecryption.common.Constant;
import com.qust.EnDecryption.common.MetaData;
import com.qust.EnDecryption.util.net.HttpMethod;
import com.qust.EnDecryption.util.net.NetTool;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.EventLoopGroup;
import lombok.extern.log4j.Log4j2;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;

@Log4j2
public class ConnectListener implements ChannelFutureListener {

    private final NetTool netTool = new NetTool();
    private final String manager = "http://localhost:8086/algorithmController/";
    private final String metaDataPath = Constant.savePathPrefix+"/mateData.json";
    private InterProcessMutex interProcessMutex;
    private EventLoopGroup eventLoopGroup;
    public ConnectListener(InterProcessMutex interProcessMutex, EventLoopGroup eventLoopGroup){
        this.interProcessMutex = interProcessMutex;
        this.eventLoopGroup = eventLoopGroup;
    }


    @Override
    public void operationComplete(ChannelFuture channelFuture) throws Exception {
        Path path = Paths.get(metaDataPath);
        CountDownLatch latch = new CountDownLatch(1);
        if (Files.exists(path)){
            log.debug("metaData文件存在");

            MetaData metaData = JSON.parseObject(path.toFile().toURI().toURL()).to(MetaData.class);

            Set<Integer> existing = metaData.getAlgorithmMetaDataMap().keySet();
            Set<Integer> standard = Constant.META_DATA.getAlgorithmMetaDataMap().keySet(); // ZkNodeProvide#register中赋值,赋值为标准的元数据

            Set<Integer> difference = new HashSet<>(standard); // 计算差集
            difference.removeAll(existing);

            Constant.META_DATA.getAlgorithmMetaDataMap().clear();// 清除,用于记录本地算法元数据

            if (!difference.isEmpty()){
                log.debug("缺失算法,开始追赶");
                log.debug("加分布式锁追赶");

                eventLoopGroup.next().execute(()->{
                    try{
                        interProcessMutex.acquire(); // zk分布式锁,获取锁,如果获取不了就堵塞在此
                        latch.countDown();
                        while (true){
                            log.debug("isCatchUp:{}",Constant.isCatchUp);
                            if (Constant.isCatchUp){
                                interProcessMutex.release();
                                log.debug("释放分布式锁");
                                break;
                            }
                            Thread.sleep(1000);
                        }
                    }catch (Exception e){
                        throw new RuntimeException(e);
                    }
                });
                latch.await();
                Map<String ,String> address = new HashMap<>();
                address.put("address", Constant.ip+":"+Constant.port);
                address.put("missing",JSON.toJSONString(difference));
                netTool.request(manager +"catchUp/",HttpMethod.GET,null,null,address);

            }else {
                log.debug("没有缺失的算法,不用追赶");
                Constant.isCatchUp = true;
            }

        }else {
            log.debug("metaData不存在");
            log.debug("开始追赶");
            log.debug("加分布式锁追赶");

            eventLoopGroup.next().execute(()->{
                try{
                    interProcessMutex.acquire(); // zk分布式锁
                    while (true){
                        log.debug("isCatchUp:{}",Constant.isCatchUp);
                        if (Constant.isCatchUp){
                            interProcessMutex.release();
                            log.debug("释放分布式锁");
                            break;
                        }
                        Thread.sleep(1000);
                    }
                }catch (Exception e){
                    throw new RuntimeException(e);
                }

            });

            Set<Integer> integers = Constant.META_DATA.getAlgorithmMetaDataMap().keySet();
            Map<String ,String > address = new HashMap<>();
            address.put("address", Constant.ip+":"+Constant.port);
            address.put("missing", JSON.toJSONString(integers));
            netTool.request(manager +"catchUp/",HttpMethod.POST,null,null,address);

        }
    }
}
